{{>licenseInfo}}
package {{apiPackage}}

import java.io.IOException

{{#imports}}import {{import}}
{{/imports}}

{{#jackson}}
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.core.type.TypeReference
{{/jackson}}
{{#gson}}
import com.google.gson.reflect.TypeToken
import com.google.gson.annotations.SerializedName
{{/gson}}
{{#moshi}}
import com.squareup.moshi.Json
{{/moshi}}

import io.vertx.core.Vertx
import io.vertx.core.http.RequestOptions
import io.vertx.core.http.HttpMethod
import io.vertx.core.buffer.Buffer
import io.vertx.core.Future
import io.vertx.ext.web.client.WebClient
import io.vertx.uritemplate.UriTemplate

{{#useCoroutines}}
import io.vertx.kotlin.coroutines.coAwait
import io.vertx.kotlin.coroutines.dispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
{{/useCoroutines}}

import {{packageName}}.infrastructure.*

@Suppress ("UNUSED")
{{#operations}}
{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}open {{/nonPublicApi}}class {{classname}}(basePath: kotlin.String = ApiClient.defaultBasePath, accessToken: String? = null, apiKey: MutableMap<String, String> = mutableMapOf(), apiKeyPrefix: MutableMap<String, String> = mutableMapOf(), username: String? = null, password: String? = null, vertx: Vertx): ApiClient(basePath, accessToken, apiKey, apiKeyPrefix, username, password, vertx) {
    {{#operation}}
    {{#allParams}}
    {{#isEnum}}
    /**
     * enum for parameter {{paramName}}
     */
     {{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}enum class {{enumName}}{{operationIdCamelCase}}({{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}val value: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}kotlin.String{{/isContainer}}) {
     {{^enumUnknownDefaultCase}}
     {{#allowableValues}}
     {{#enumVars}}
     {{#moshi}}
     @Json(name = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}
     {{/moshi}}
     {{#gson}}
     @SerializedName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}
     {{/gson}}
     {{#jackson}}
     @JsonProperty(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}
     {{/jackson}}
     {{#kotlinx_serialization}}
     @SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}
     {{/kotlinx_serialization}}
     {{/enumVars}}
     {{/allowableValues}}
     {{/enumUnknownDefaultCase}}
     {{#enumUnknownDefaultCase}}
     {{#allowableValues}}
     {{#enumVars}}
     {{^-last}}
     {{#moshi}}
     @Json(name = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}),
     {{/moshi}}
     {{#gson}}
     @SerializedName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}),
     {{/gson}}
     {{#jackson}}
     @JsonProperty(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}),
     {{/jackson}}
     {{#kotlinx_serialization}}
     @SerialName(value = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}),
     {{/kotlinx_serialization}}
     {{/-last}}
     {{/enumVars}}
     {{/allowableValues}}
     {{/enumUnknownDefaultCase}}
     }

    {{/isEnum}}
    {{/allParams}}
    /**
     * {{{httpMethod}}} {{#sanitizePathComment}}{{{path}}}{{/sanitizePathComment}}
     * {{summary}}
     * {{notes}}
     {{#allParams}}* @param {{{paramName}}} {{description}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}{{/required}}
     {{/allParams}}* @return {{#returnType}}{{{returnType}}}{{#nullableReturnType}}{{^isResponseOptional}} or null{{/isResponseOptional}}{{/nullableReturnType}}{{#isResponseOptional}} or null{{/isResponseOptional}}{{/returnType}}{{^returnType}}void{{/returnType}}
     * @throws IllegalStateException If the request is not correctly configured
     * @throws IOException Rethrows the OkHttp execute method exception
     * @throws UnsupportedOperationException If the API returns an informational or redirection response
     * @throws ClientException If the API returns a client error response
     * @throws ServerException If the API returns a server error response
     */{{#returnType}}
    @Suppress("UNCHECKED_CAST"){{/returnType}}
    @Throws(IllegalStateException::class, IOException::class, UnsupportedOperationException::class, ClientException::class, ServerException::class)
    {{#isDeprecated}}
    @Deprecated(message = "This operation is deprecated.")
    {{/isDeprecated}}
    {{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}{{#useCoroutines}}suspend {{/useCoroutines}}fun {{operationId}}({{#allParams}}{{{paramName}}}: {{#isEnum}}{{#isContainer}}kotlin.collections.List<{{enumName}}{{operationIdCamelCase}}>{{/isContainer}}{{^isContainer}}{{enumName}}{{operationIdCamelCase}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#required}}{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{/required}}{{^required}}?{{#defaultValue}} = {{^isNumber}}{{{defaultValue}}}{{/isNumber}}{{#isNumber}}{{{dataType}}}("{{{defaultValue}}}"){{/isNumber}}{{/defaultValue}}{{^defaultValue}} = null{{/defaultValue}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) : {{^useCoroutines}}Future<{{/useCoroutines}}{{#returnType}}{{{returnType}}}{{#nullableReturnType}}{{^isResponseOptional}}?{{/isResponseOptional}}{{/nullableReturnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Unit{{/returnType}}{{^useCoroutines}}>{{/useCoroutines}} {
        return {{operationId}}WithHttpInfo({{#allParams}}{{{paramName}}} = {{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}).map { localVarResponse ->
            when (localVarResponse.responseType) {
                ResponseType.Success -> {{#returnType}}(localVarResponse as Success<*>).data as {{{returnType}}}{{#nullableReturnType}}{{^isResponseOptional}}?{{/isResponseOptional}}{{/nullableReturnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Unit{{/returnType}}
                ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.")
                ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.")
                ResponseType.ClientError -> {
                    val localVarError = localVarResponse as ClientError<*>
                    throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse)
                }
                ResponseType.ServerError -> {
                    val localVarError = localVarResponse as ServerError<*>
                    throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse)
                }
            }
        }{{#useCoroutines}}.coAwait(){{/useCoroutines}}
    }

    /**
     * {{{httpMethod}}} {{#sanitizePathComment}}{{{path}}}{{/sanitizePathComment}}
     * {{summary}}
     * {{notes}}
     {{#allParams}}* @param {{{paramName}}} {{description}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}{{/required}}
     {{/allParams}}* @return ApiResponse<{{#returnType}}{{{returnType}}}?{{/returnType}}{{^returnType}}Unit?{{/returnType}}>
     * @throws IllegalStateException If the request is not correctly configured
     * @throws IOException Rethrows the OkHttp execute method exception
     */{{#returnType}}
    @Suppress("UNCHECKED_CAST"){{/returnType}}
    @Throws(IllegalStateException::class, IOException::class)
    {{#isDeprecated}}
    @Deprecated(message = "This operation is deprecated.")
    {{/isDeprecated}}
    {{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun {{operationId}}WithHttpInfo({{#allParams}}{{{paramName}}}: {{#isEnum}}{{#isContainer}}kotlin.collections.List<{{enumName}}{{operationIdCamelCase}}>{{/isContainer}}{{^isContainer}}{{enumName}}{{operationIdCamelCase}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}?{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) : Future<ApiResponse<{{#returnType}}{{{returnType}}}?{{/returnType}}{{^returnType}}Unit?{{/returnType}}>> {
        val vertxClient = WebClient.create(vertx)
        val request = vertxClient.requestAbs(HttpMethod.{{httpMethod}}, UriTemplate.of("$basePath{{{path}}}"{{#pathParams}}.replace("{"+"{{baseName}}"+"}", encodeURIComponent({{#isContainer}}{{paramName}}.joinToString(","){{/isContainer}}{{^isContainer}}{{{paramName}}}{{#isEnum}}{{^required}}?{{/required}}.value{{/isEnum}}.toString(){{/isContainer}})){{/pathParams}}))

        {{#hasFormParams}}request.putHeader("Content-Type", {{^consumes}}"multipart/form-data"{{/consumes}}{{#consumes.0}}"{{{mediaType}}}"{{/consumes.0}}){{/hasFormParams}}
        {{#headerParams}}{{{paramName}}}{{^required}}?{{/required}}.apply { request.putHeader("{{baseName}}", {{#isContainer}}this.joinToString(separator = collectionDelimiter("{{collectionFormat}}")){{/isContainer}}{{^isContainer}}this.toString(){{/isContainer}})}{{/headerParams}}
        {{^hasFormParams}}{{#hasConsumes}}
            {{#consumes}}
                    request.putHeader("Content-Type", "{{{mediaType}}}")
            {{/consumes}}
        {{/hasConsumes}}{{/hasFormParams}}
        {{#hasProduces}}request.putHeader("Accept", "{{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}"){{/hasProduces}}

        {{#hasFormParams}}
        val form = io.vertx.core.MultiMap.caseInsensitiveMultiMap();
        {{#formParams}}
        {{{paramName}}}{{^required}}?{{/required}}.let { form.add("{{{baseName}}}", {{{paramName}}}{{#isEnum}}{{^required}}?{{/required}}.value{{/isEnum}}{{^isString}}.toString(){{/isString}}) }
        {{/formParams}}
        {{/hasFormParams}}

        {{#hasQueryParams}}
        {{#queryParams}}
        {{{paramName}}}{{^required}}?{{/required}}.let { request.queryParams().add("{{baseName}}", {{#isContainer}}toMultiValue(it.toList(), "{{collectionFormat}}"){{/isContainer}}{{^isContainer}}listOf({{#isDateTime}}parseDateToQueryString(it){{/isDateTime}}{{#isDate}}parseDateToQueryString(it){{/isDate}}{{^isDateTime}}{{^isDate}}it.toString(){{/isDate}}{{/isDateTime}}){{/isContainer}}) }
        {{/queryParams}}
        {{/hasQueryParams}}

        {{#authMethods}}
        {{#isApiKey}}
        if (apiKey["{{keyParamName}}"] != null) {
            if (apiKeyPrefix["{{keyParamName}}"] != null) {
                {{#isKeyInHeader}}
                request.putHeader("{{keyParamName}}", apiKeyPrefix["{{keyParamName}}"]!! + " " + apiKey["{{keyParamName}}"]!!)
                {{/isKeyInHeader}}
                {{#isKeyInQuery}}
               request.queryParams().add("{{keyParamName}}", apiKeyPrefix["{{keyParamName}}"]!! + " " + apiKey["{{keyParamName}}"]!!)
                {{/isKeyInQuery}}
            } else {
                {{#isKeyInHeader}}
                request.putHeader("{{keyParamName}}", apiKey["{{keyParamName}}"]!!)
                {{/isKeyInHeader}}
                {{#isKeyInQuery}}
                request.queryParams().add("{{keyParamName}}", apiKey["{{keyParamName}}"]!!)
                {{/isKeyInQuery}}
            }
        }
        {{/isApiKey}}
        {{#isBasic}}
        {{#isBasicBasic}}
        username?.let { username ->
            password?.let { password ->
                request.basicAuthentication(username, password)
            }
        }
        {{/isBasicBasic}}
        {{#isBasicBearer}}
        accessToken?.let { accessToken ->
           request.bearerTokenAuthentication(accessToken)
        }
        {{/isBasicBearer}}
        {{/isBasic}}
        {{#isOAuth}}
        accessToken?.let { accessToken ->
            request.bearerTokenAuthentication(accessToken)
        }
        {{/isOAuth}}
        {{/authMethods}}

        return request
            {{#hasBodyParam}}
            .sendBuffer(responseBody({{#bodyParams}}{{{paramName}}}{{/bodyParams}}))
            {{/hasBodyParam}}
            {{^hasBodyParam}}
            .send()
            {{/hasBodyParam}}
            .map {
                val apiResponse: ApiResponse<{{#returnType}}{{{returnType}}}?{{/returnType}}{{^returnType}}Unit?{{/returnType}}> = handleResponse(it)
                apiResponse
            }
    }

    {{/operation}}

    private inline fun <reified T: Any?> responseBody(body: T): Buffer {
        {{#moshi}}
        return Buffer.buffer(Serializer.moshi.adapter(T::class.java).toJson(body))
        {{/moshi}}
        {{#gson}}
        return Buffer.buffer(Serializer.gson.toJson(body, T::class.java))
        {{/gson}}
        {{#jackson}}
        return Buffer.buffer(Serializer.jacksonObjectMapper.writeValueAsBytes(body))
        {{/jackson}}
    }

}
{{/operations}}
